﻿#include"stdafx.h"
#include "ServerDB.h"


bool ServerDB::Table_Alter_Add(const char*tname, string db,vector<string>field_info, string &msg) {
	cur_db = db.c_str();
	if (cur_db == "") {
		msg = "Please choose a database !";
		return false;
	}

	CString  tbPath; 
	tbPath = L"data\\" + cur_db + L"\\" + cur_db + L".tb";
	if (!IsTable(tbPath, tname)) {
		msg = "Incorrect table name !";
		return false;
	}
	CString DBPath, Ctname;
	Ctname = tname; 
	Table_Tdf tdf;
	vector<Table_Tdf>vec_tdf;
	DBPath = L"data\\" + cur_db + L"\\" + Ctname + L".tdf";

	file.Open(DBPath, CFile::modeReadWrite | CFile::typeBinary, NULL);
	while (file.Read(&tdf, sizeof(tdf))) {
		//判断新增的字段名是否重复
		if (strcmp(tdf.name, field_info[0].c_str()) == 0) {
			file.Close();
			msg = " Duplicate column! ";
			return false;
		}
		vec_tdf.push_back(tdf);
	}
	tdf.index = false;
	Conversion(tdf.name, field_info[0].c_str());
	Conversion(tdf.type, field_info[1].c_str());
	tdf.param = stoi(field_info[2]);
	tdf.mtime = CTime::GetCurrentTime();
	tdf.order = vec_tdf.back().order + vec_tdf.back().param;
	for (unsigned int j = 3; j < field_info.size(); j++) {
		Conversion(tdf.intergrities[j - 3], field_info[j].c_str());
	}
	Conversion(tdf.intergrities[field_info.size() - 3], "o");
	vec_tdf.push_back(tdf);
	file.Write(&tdf, sizeof(tdf));
	file.Close();

	//修改记录
	int old_lenth, new_lenth;
	old_lenth = vec_tdf.back().order;
	new_lenth = old_lenth + vec_tdf.back().param;
	char *temp_arr;
	temp_arr = new char[new_lenth];
	memset(temp_arr, 0, new_lenth);
	CString temp_path;
	CFile temp_file;
	temp_path = L"data\\" + cur_db + L"\\" + Ctname + L".temp_trd";
	temp_file.Open(temp_path, CFile::modeCreate | CFile::typeBinary, NULL);
	temp_file.Close();
	temp_file.Open(temp_path, CFile::modeWrite | CFile::typeBinary, NULL);

	DBPath = L"data\\" + cur_db + L"\\" + Ctname + L".trd";
	file.Open(DBPath, CFile::modeRead | CFile::typeBinary, NULL);

	while (file.Read(temp_arr, old_lenth)) {
		temp_file.Write(temp_arr, new_lenth);
	}
	file.Close(); 
	temp_file.Close();
	delete temp_arr;
	file.Remove(DBPath);
	file.Rename(temp_path, DBPath);
	msg = "successful !";
	return true;
}

bool ServerDB::Table_Alter_Drop(const char*tname, string db,string field, string &msg) {
	cur_db = db.c_str();
	if (cur_db == "") {
		msg = "Please choose a database !";
		return 0;
	}
	CString  tbPath; 
	tbPath = L"data\\" + cur_db + L"\\" + cur_db + L".tb";
	if (!IsTable(tbPath, tname)) {
		msg = "Incorrect table name !";
		return false;
	}
	int size, pos;
	CString DBPath, Ctname; 
	Ctname = tname;
	bool index = false,judge=false;
	Table_Tdf tdf; 
	vector<Table_Tdf>vec_tdf;
	DBPath = L"data\\" + cur_db + L"\\" + Ctname + L".tdf";

	file.Open(DBPath, CFile::modeRead | CFile::typeBinary, NULL);
	while (file.Read(&tdf, sizeof(tdf))) {
		if (strcmp(tdf.name, field.c_str()) == 0) {
			pos = tdf.order;
			size = tdf.param;
			index = true;
			judge = tdf.index;
		}
		else {
			if (index) {
				tdf.order -= size;
			}
			vec_tdf.push_back(tdf);
		}
	}
	file.Close();

	if (!index) {
		msg = "Invalid column ";
		return 0;
	}
	if (judge) {
		file.Remove(L"data\\" + cur_db + L"\\" + Ctname+L"_"+field.c_str()+".tid");
	}
	file.Remove(DBPath);
	file.Open(DBPath, CFile::modeCreate | CFile::typeBinary, NULL);
	file.Close();
	file.Open(DBPath, CFile::modeWrite | CFile::typeBinary, NULL);
	for (unsigned int i = 0; i < vec_tdf.size(); i++)
		file.Write(&vec_tdf[i], sizeof(vec_tdf[i]));
	file.Close();


	int new_lenth = vec_tdf.back().order + vec_tdf.back().param;
	char *front_arr, *back_arr, *placeholder;
	front_arr = new char[pos];
	back_arr = new char[new_lenth - pos];
	placeholder = new char[size];

	memset(front_arr, 0, pos);
	memset(back_arr, 0, new_lenth - pos);

	CString temp_path;
	CFile temp_file;
	temp_path = L"data\\" + cur_db + L"\\" + Ctname + L".temp_trd";
	temp_file.Open(temp_path, CFile::modeCreate | CFile::typeBinary, NULL);
	temp_file.Close();
	temp_file.Open(temp_path, CFile::modeWrite | CFile::typeBinary, NULL);

	DBPath = L"data\\" + cur_db + L"\\" + Ctname + L".trd";
	file.Open(DBPath, CFile::modeRead | CFile::typeBinary, NULL);

	long fileLenth = file.GetLength();
	long position = 0;
	while (position<fileLenth) {
		file.Read(front_arr, pos);
		file.Read(placeholder, size);
		file.Read(back_arr, new_lenth - pos);
		temp_file.Write(front_arr, pos);
		temp_file.Write(back_arr, new_lenth - pos);
		memset(front_arr, 0, pos);
		memset(back_arr, 0, new_lenth - pos);
		position += new_lenth + size;
	}
	file.Close();
	temp_file.Close();

	delete front_arr;
	delete placeholder;
	delete back_arr;

	file.Remove(DBPath);
	file.Rename(temp_path, DBPath);
	msg = "successful !";
	return true;
}

bool ServerDB::Table_Alter_Modify(const char*tname, string db,vector<string>field_info, string &msg) {
	cur_db = db.c_str();
	if (cur_db == "") {
		msg = "Please choose a database !";
		return 0;
	}
	CString  tbPath; 
	tbPath = L"data\\" + cur_db + L"\\" + cur_db + L".tb";
	if (!IsTable(tbPath, tname)) {
		msg = "Incorrect table name !";
		return false;
	}
	int pos, old_size, new_size;
	CString DBPath, Ctname;
	Ctname = tname;
	bool index = false;
	Table_Tdf tdf;
	vector<Table_Tdf>vec_tdf;
	DBPath = L"data\\" + cur_db + L"\\" + Ctname + L".tdf";

	file.Open(DBPath, CFile::modeReadWrite | CFile::typeBinary, NULL);
	while (file.Read(&tdf, sizeof(tdf))) {
		if (index) {
			tdf.order = vec_tdf.back().order + vec_tdf.back().param;
		}
		if (strcmp(tdf.name, field_info[0].c_str()) == 0) {
			if (tdf.index|| strcmp(tdf.type, "4") != 0) {
				file.Close();
				msg = "Column does not allow modified  !";
				return false;
			}
			pos = tdf.order;
			old_size = tdf.param;
			Conversion(tdf.type, field_info[1].c_str());
			tdf.mtime = CTime::GetCurrentTime();
			tdf.param = atoi(field_info[2].c_str());
			for (unsigned int j = 3; j < field_info.size(); j++) {
				Conversion(tdf.intergrities[j - 3], field_info[j].c_str());
			}
			Conversion(tdf.intergrities[field_info.size() - 3], "o");
			new_size = tdf.param;
			index = true;
		}
		vec_tdf.push_back(tdf);
	}

	if (!index) {
		file.Close();
		msg = " Invalid column! ";
		return false;
	}

	file.SeekToBegin();
	for (unsigned int i = 0; i < vec_tdf.size(); i++)
		file.Write(&vec_tdf[i], sizeof(vec_tdf[i]));
	file.Close();

	int lenth, offset, off;
	if (new_size >= old_size) {
		offset = 0;
		off = new_size - old_size;
	}
	else {
		offset = old_size - new_size;
		off = 0;
	}
	lenth = vec_tdf.back().order + vec_tdf.back().param - new_size - pos;
	pos += min(new_size, old_size);

	char *front_arr, *back_arr, *placeholder;

	front_arr = new char[pos];
	back_arr = new char[lenth];
	placeholder = new char[off];
	memset(front_arr, 0, pos);
	memset(back_arr, 0, lenth);
	memset(placeholder, 0, off);

	CString temp_path;
	CFile temp_file;
	temp_path = L"data\\" + cur_db + L"\\" + Ctname + L".temp_trd";
	temp_file.Open(temp_path, CFile::modeCreate | CFile::typeBinary, NULL);
	temp_file.Close();
	temp_file.Open(temp_path, CFile::modeWrite | CFile::typeBinary, NULL);

	DBPath = L"data\\" + cur_db + L"\\" + Ctname + L".trd";
	file.Open(DBPath, CFile::modeRead | CFile::typeBinary, NULL);
	long fileLenth = file.GetLength();
	int old_lenth = vec_tdf.back().order + vec_tdf.back().param - new_size + old_size;
	long position = 0;
	while (position<fileLenth) {
		file.Read(front_arr, pos);
		file.Seek(offset, file.current);
		file.Read(back_arr, lenth);
		temp_file.Write(front_arr, pos);
		temp_file.Write(placeholder, off);
		temp_file.Write(back_arr, lenth);
		memset(front_arr, 0, pos);
		memset(back_arr, 0, lenth);
		memset(placeholder, 0, off);
		position += old_lenth;
	}
	file.Close();
	temp_file.Close();
	delete placeholder;
	delete front_arr;
	delete back_arr;
	file.Remove(DBPath);
	file.Rename(temp_path, DBPath);
	msg = "successful !";
	return true;

}

